知っておくとちょっと便利?SageMaker Processingの仕様とProccesorとScriptProcessor
おはこんハロチャオ~!何者(なにもん)なんじゃ?じょんすみすです。
SageMaker Processing(以下Processing)を使う時、SageMaker Python SDK(以下SDK)を利用してジョブを実行しているケースが多いかと思います。 Processingを含めてSageMakerの各種ジョブは他のAWSのサービスと同様にAPIを使ってのアクセスです。 そのため、このSDKもAWS CLIやBoto3などと同様にAPI呼び出しのラッパーとして提供されているものとなりますが、scikit-learn風のインターフェースで扱う仕組みを提供しているわけです。
SDKからProcessingを利用するときに Processor
や ScriptProcessor
, SKLearnProcessor
, PySparkProcessor
など様々なクラスが提供されています。
こられについて、実は同様のAPIがそのままあって一対一で紐づいているという訳ではないのです。
今回はProcessor
と ScriptProcessor
の関係を見ることでその話をしたいと思います。
Processingのおさらい
まずは、Processingの基本的な動きをおさらいしておきます。
Processingの動きを簡単にまとめると以下のような仕組みになります。
- 任意のバッチ処理を動かすコンテナ実行環境
- 複数のインスタンスを起動しての分散処理が可能
- 実行時に入力として指定したS3のプレフィックスを含むデータをコンテナ内にコピーする
- 処理完了時に出力として指定したコンテナ内のディレクトリ内のファイルをS3にコピーする
- コンテナ実行時のENTRYPOINTやCMDに相当するコマンドライン引数を指定可能
Processingにはどのような機能があるかの説明はこれでほぼすべてとなります。 非常にシンプルで使いやすそうなコンテナ実行環境ですね。
ProcessorとScriptProcessor
さて、Processingの動作に関する仕組みが分かったところで、これを使ってSDK側の様々なクラスがどのように自身が提供する仕組みを実現しているのか見てきましょう。
最初に確認しておくこととして、SDKの中身をどうやって知るんだ?という話ですが、 これはGitHubでソースが公開されています。
そのため、SDKがどのような処理をしてどのようなにAPIアクセスしているのかは確認することが可能です。
まずは特にプレフィックスのつかないProcessorです。
すでにSDKを使っている方であればご存じかとは思いますが、 Processorクラスのインスタンス作成時や実行時に上記の仕組みで必要となるような項目を設定しています。 CreateProcessingJob - Amazon SageMakerなどと比較すると、これらはAPIが要求するJSON形式の入力とそれぞれ対応する関係があることが確認できます。
さて、これを踏まえてScriptProcessorのことを考えたいと思うのですが、create-processing-jobにはScriptProcessorにおけるcode引数に相当するが無さそうです。 ScriptProcessorはどのように実行時に利用するPythonスクリプトを利用しているのでしょうか? これは、Processing自体の機能ではなく、SDKのScrpitProcessorが以下のような処理を先に実行したうえでProcessing Jobを実行するという動きになっています。
- code引数で指定したスクリプトがローカルファイルの場合S3にアップロード
- code引数で指定したスクリプトのS3のパスを実行時の入力(Inputs)に追加する
ContainerEntrypoint
の値をそのファイルにする
という動きで実現しています。 そのため、この実行時にファイルを指定するという仕組みはProcessing自体の機能ではなく、 SDKが便利に使えるようにラップしたScriptProcessorの機能となっているわけです。
これらの処理はprocessing.pyで実装されているためその動きが確認可能です。
流れを追ってみたい方は以下のあたりを参照してみてください。
- ScriptProcessorはProcessroのサブクラスである
- 内部で引数を処理する_normalize_args関数を呼び出している
- _normalize_args関数はProceccorクラスで定義されており_include_code_in_inputs関数を呼び出している
- _include_code_in_inputs関数はProcessor, ScriptProcessorの両方で定義されておりScriptProcessor方ではcodeをInputsに加える処理をしている
- _normalize_args関数に戻り、その中の _set_entrypoint関数でこのファイルパスをENTRYPOINTに設定
- run関数に戻り、ジョブを実行
知っておくとどういう時に便利なの?
そのため、Processorクラスを利用していても同様の仕組みを自前で実装することも可能です。 とは言え、それだとただの車輪の再発明です。
この仕組みを知っておくと以下のような状況に対応できます。
- ScriptProcessor相当の仕組みを使いたい
- ファイルはローカルにあるものを指定する必要がある
- S3のどこのパスにどんなファイルをアップロードするか厳密に管理したい
ScriptProcessorはローカルファイルをS3にアップロードするところまでラップしているので、 その部分で勝手にファイルを上げられると困るけど、あらかじめS3にあげておいてそのパスを指定するのは難しいという状況に遭遇したら試してみてください。
おわりに
今回は、SageMaker ProcessingをSageMaker Python SDKから利用する際のちょっとした裏側をのぞき見てみました。
知っていても役立つ機会はそれほど多くないかもしれませんが、たまにこういったところを見てみると面白い発見があったりするものです。